#ifndef _SCROLL_H_
#define _SCROLL_H_

#pragma warning ( disable: 4786 )
#include <list>
#include <functional>

#include <interfacelib/Window/Window.h>
#include <interfacelib/Window/Panel.h>
#include <utillib/string/string.h>

namespace interfacelib
{
	namespace Window
	{
		template < class _Ty >
		class Scroll : public Panel
		{
		protected:
			typedef std::list < _Ty > listElement;
		public:
			Scroll() : m_currentFirstObject( NULL ), m_linePerPage( 1 ), m_lineHeihgt( 0 ), m_xpos( 0 ), m_ypos( 0 ), m_selectObject( NULL )
			{
			};
			virtual ~Scroll()
			{
				removeAllElement();
			};

			bool create( const char *imageName, int x, int y, int width, int height, DWORD attribute = VISIBLE )
			{
				setMovable( false );
				bool result = Window::create( imageName, x, y, attribute);
				setWindowPos( x, y, width, height );
				return ( result );
			};

			void addElement( _Ty object )
			{
				m_listElement.push_back( object );
			};
			
			virtual void drawScroll()
			{
				bool drawMode = false;
				int count = 0;
				{
					listElement::const_iterator iter_end( m_listElement.end() );
					for ( listElement::const_iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						_Ty object = ( *iter );
						if ( !m_currentFirstObject ) m_currentFirstObject = object;
						if ( object == m_currentFirstObject ) drawMode = true;
						if ( drawMode )
						{
							if ( !drawElement( m_xpos, m_ypos + ( m_lineHeihgt * count ), object ) ) break;
							count++;
						}

						if ( count == m_linePerPage ) break;
					}
				}
			}
			virtual bool drawElement( int x, int y, _Ty object ) = NULL;

			virtual void removeElement( _Ty object )
			{
				{
					listElement::iterator iter_end( m_listElement.end() );
					for ( listElement::iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						if ( *iter == object )
						{
							removeObject( object );
							m_listElement.erase( iter ) ; 
							return;
						}
					}
				}
			};

			_Ty getObject( int pos )
			{
				{
					int i = 0;
					listElement::iterator iter_end( m_listElement.end() );
					for ( listElement::iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						if ( i == pos )
							return ( *iter );
						i++;
					}
					return ( NULL );
				}
			};

			virtual void removeObject( _Ty object )
			{
				if ( object == m_currentFirstObject ) m_currentFirstObject = NULL;
				if ( object == m_selectObject ) m_selectObject = NULL;
				SAFE_DELETE( object );
			}

			virtual void onLButtonDblClk( UINT flags, POINT point )
			{
				m_selectObject = getObject( point );
				Panel::onLButtonDblClk( flags, point );
			}
			virtual void onLButtonDown( UINT flags, POINT point )
			{
				m_selectObject = getObject( point );
				Panel::onLButtonDown( flags, point );
			}
			virtual void onRButtonDown( UINT flags, POINT point )
			{
				m_selectObject = getObject( point );
				Panel::onRButtonDown( flags, point );
			}

			int getLineCount(){ return ( m_listElement.size() );};

			void setFont( HFONT font ) { m_font = font; };
			void setLinePerPage( int count ){ m_linePerPage = count ; };
			void setLineHeight( int height )
			{
				m_lineHeihgt = height;
			};
			void setXpos( int pos ){ m_xpos = pos; };
			void setYpos( int pos ){ m_ypos = pos; };
			virtual	void draw( Window *checkWindow = NULL )
			{
				Panel::draw( checkWindow );
				drawScroll();
			}
			bool insertElement( _Ty , _Ty findObject = NULL )
			{
				{
					if ( !findObject )
					{
						m_listElement.insert( m_listElement.begin(), object );
						return ( true );
					}
					listElement::iterator iter_end( m_listElement.end() );
					for ( listElement::iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						if ( *iter == findObject )
						{
							m_listElement.insert( iter, object );
							return ( true );
						}
					}
				}
				return ( false );
			};
			
			bool scrollUp( int count )
			{
				{
					listElement::reverse_iterator iter_end( m_listElement.rend() );
					for ( listElement::reverse_iterator iter = m_listElement.rbegin(); iter != iter_end ; ++iter )
					{
						if ( *iter == m_currentFirstObject )
						{
							_Ty object = NULL;
							for ( int i = 0 ; i < count; i++ )
							{
								++iter;
								if ( iter == m_listElement.rend() )
								{
									return ( true );
								}
								object = ( *iter );
							}
							m_currentFirstObject = object;
							return ( true );
						}
					}
				}
				return ( false );
			};
			bool scrollDown( int count )
			{
				{
					if ( getLineCount() < m_linePerPage ) return ( false );
					listElement::const_iterator iter_end( m_listElement.end() );
					for ( listElement::const_iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						if ( *iter == m_currentFirstObject )
						{
							_Ty object = NULL;
							for ( int i = 0 ; i < count; i++ )
							{
								++iter;
								if ( iter == m_listElement.end() ) 
								{
									return ( true );
								}
								object = ( *iter );
							}
							m_currentFirstObject = object;
							return ( true );
						}
					}
				}
				return ( false );
			};
			
			void removeAllElement()
			{
				{
					listElement::const_iterator iter_end( m_listElement.end() );
					for ( listElement::const_iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						_Ty object = ( *iter );
						SAFE_DELETE( object );
					}
					m_listElement.clear();
					m_currentFirstObject = NULL;
					m_selectObject = NULL;
				}
			}
			POINT *getElementPoint(){ return ( &m_elementPoint );	};
			POINT *getClickPoint(){ return ( &m_clickPoint );	};
			_Ty getSelectObject(){ return ( m_selectObject ); };
		protected:
			_Ty getObject( POINT point )
			{
				bool drawMode = false;
				POINT windowPoint;
				getWindowPos( &windowPoint );
				
				point.x -= windowPoint.x;
				point.y -= windowPoint.y;
				ZeroMemory( &m_elementPoint, sizeof( POINT ) ) ;
				m_elementPoint.y += m_ypos;
				m_elementPoint.x += m_xpos;
				CopyMemory( &m_clickPoint, &point, sizeof( POINT ) );
				
				BYTE count = 0;
				{
					listElement::const_iterator iter_end( m_listElement.end() );
					for ( listElement::const_iterator iter = m_listElement.begin(); iter != iter_end ; ++iter )
					{
						_Ty object = ( *iter );
						if ( !m_currentFirstObject ) m_currentFirstObject = object;
						if ( object == m_currentFirstObject ) drawMode = true;
						if ( drawMode )
						{
							if ( ( point.y >= m_elementPoint.y ) && ( point.y < m_elementPoint.y + m_lineHeihgt ) )
							{
								return ( object );
							}
							m_elementPoint.y += m_lineHeihgt;
							count++;
						}
						
						if ( count == m_linePerPage ) break;
					}
				}
				return ( NULL );
			}

			HFONT m_font;
			POINT m_elementPoint;
			POINT m_clickPoint;
			int m_xpos;
			int m_ypos;
			int m_linePerPage;
			int m_lineHeihgt;


			listElement m_listElement;
			_Ty m_currentFirstObject;
			_Ty m_selectObject;
		//	ClipArea m_bgInfo;
		};

		class ScrollWithString : public Scroll < utillib::string::String * >
		{
		public:
			ScrollWithString();
			virtual ~ScrollWithString();

		public:
			void addString( const char *string );
			virtual bool drawElement( int x, int y, utillib::string::String *object );
			bool isExist( const char *findObject );
			void removeString( const char *string  );
		};
	};
}

#endif